package com.ssg.poultry.websocket.admin;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import com.ssg.poultry.exception.SerialPortException;
import com.ssg.poultry.protocol.CommandHex;
import com.ssg.poultry.service.SerialPortListener;
import com.ssg.poultry.service.SerialPortService;
import com.ssg.poultry.util.ByteUtil;
import com.ssg.poultry.util.TimeUtil;
import com.ssg.poultry.websocket.BaseWebSocket;

import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;

@ServerEndpoint("/ws/admin/console")
public class ConsoleWebSocket extends BaseWebSocket{
	private static final SerialPortService sps = new SerialPortService(115200, 1);
	private static SerialPort port = null;
	private static final Set<ConsoleWebSocket> wss = new CopyOnWriteArraySet<>();
	private Map<String,String> data = new ConcurrentHashMap<>();
	
	static {
		sps.setListener(new SerialPortListener() {
			
			@Override
			public void on(String event, byte[] data) {
				for(ConsoleWebSocket ws:wss) {
					try {
						ws.session.getBasicRemote().sendText(event+":"+TimeUtil.hhmmss()+":"+event.toLowerCase()+":"+ByteUtil.bytesToHex(data));
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
			}
		});
	}
	
	@Override
	@OnOpen
	public void onOpen(Session session, EndpointConfig config) {
		super.onOpen(session, config);
		logger.debug("ws open.");
		wss.add(this);
		
	}

	@Override
	@OnMessage
	public void onMessage(Session session, String msg) {
		logger.debug("ws onmessage:"+session.getId()+msg);
		if(msg == null || "".equals(msg)) {
			return;
		}
		int x = msg.indexOf(":");
		if(x<0) {
			return;
		}
		String command = msg.substring(0, x);
		String content = msg.substring(x+1);
		if("conn".equals(command)) {
			
			logger.debug("conn-"+content);
			try {
				if(port != null) {
					logger.debug("close port.");
					port.close();
					port = null;
				}
				
				if(port == null) {
					logger.debug("try conn port");
					port = sps.connPort(content);
					logger.debug("conn port end:"+port);
				}
				try {
					sps.writeHex(port, CommandHex.CONN);
				} catch (SerialPortException e) {
					this.sendLog("log", "连接失败，发送数据失败："+CommandHex.CONN);
				}
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				try {
					byte[] connRes = sps.readFromPort(port);
					String hex = ByteUtil.bytesToHex(connRes);
					if(hex.startsWith(CommandHex.CONN_SUCC_PREFIX)) {
						this.sendLog("log", "连接成功。");
					}
				} catch (SerialPortException e) {
					this.sendLog("log", "发送连接指令后，硬件返回数据读取错误。");
				}
				
			} catch (NoSuchPortException e) {
				e.printStackTrace();
				this.sendLog("log", ":串口不存在:"+content);
			} catch (PortInUseException e) {
				e.printStackTrace();
				this.sendLog("log", ":串口不存在或者已被占用:"+content);
			} catch (UnsupportedCommOperationException e) {
				e.printStackTrace();
				this.sendLog("log", ":不支持的操作:"+content);
			}
		}else if("findCard".equals(command)) {
			if(port == null) {
				sendLog("log", "请先连接硬件。");
				return;
			}
			try {
				sps.writeHex(port, CommandHex.FIND_CARD);
			} catch (SerialPortException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			this.sleep(500);
			try {
				byte[] resp = sps.readFromPort(port);
				String hex = ByteUtil.bytesToHex(resp);
				if(hex.length() == CommandHex.FIND_CARD_SUCC.length()) {
					this.sendLog("log", "寻卡成功！");
				}else if(resp.length == CommandHex.FIND_CARD_FAIL.length() && CommandHex.FIND_CARD_FAIL.equals(hex)) {
					this.sendLog("log", "寻卡失败！");
				}else {
					this.sendLog("log", "寻卡失败！");
				}
			} catch (SerialPortException e) {
				
				e.printStackTrace();
			}
			
			
		}else if("killConflict".equals(command)) {
			if(port == null) {
				sendLog("log", "请先连接硬件。");
				return;
			}
			try {
				sps.writeHex(port, CommandHex.KILL_CONFLICT);
			} catch (SerialPortException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				this.sendLog("log", "防冲突失败！");
			}
			this.sleep(500);
			try {
				byte[] resp = sps.readFromPort(port);
				String hex = ByteUtil.bytesToHex(resp);
				if(hex.startsWith(CommandHex.KILL_CONFLICT_SUCC_PREFIX)) {
					String cardId = hex.substring(CommandHex.KILL_CONFLICT_SUCC_PREFIX.length()+1);
					this.data.put("cardId", cardId);
					this.sendLog("log", "防冲突成功！卡ID:"+cardId);
				}else {
					this.sendLog("log", "防冲突失败！");
				}
			} catch (SerialPortException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				this.sendLog("log", "防冲突失败！");
			}
			
		}else if("choseCard".equals(command)) {
			if(port == null) {
				sendLog("log", "请先连接硬件。");
				return;
			}
			String cardId = data.get("cardId");
			if(cardId == null || cardId.length() == 0) {
				sendLog("log", "失败，未获取卡ID，请先执行防冲突。");
				return;
			}
			try {
				sps.writeHex(port, CommandHex.CHOSE_CARD_PREFIX+cardId+"00");
				this.sleep(500);
				byte[] resp = sps.readFromPort(port);
				if(resp.length == 10) {
					sendLog("log", "选择卡成功！");
					
				}else {
					sendLog("log", "选择卡失败！");
				}
			} catch (SerialPortException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
						
		}else if("downloadPW".equals(command)) {
			int succLen = CommandHex.DOWNLAOD_PW_SUCC_PREFIX.length() + CommandHex.DOWNLAOD_PW_SUCC_SUFFIX.length()+1;
			for(int i=1;i<33;i++) {
				try {
					sps.writeHex(port, CommandHex.DOWNLOAD_PW_PREFIX+" "+ByteUtil.byteToHex(i)+" "+CommandHex.DOWNLOAD_PW_SUFFIX);
					this.sleep(200);
					byte[] resp = sps.readFromPort(port);
				} catch (SerialPortException e) {
					e.printStackTrace();
				}
			}
			this.sendLog("log", "下载密码完成！");
			
		}else if("readSector".equals(command)) {
			if(port == null) {
				sendLog("log", "请先连接硬件。");
				return;
			}
			int sectorNum = Integer.parseInt(content);
			
			int mid = (0x0C << 4) ;
			
			try {
				sps.writeHex(port, CommandHex.READ_SECTOR_PREFIX+ByteUtil.byteToHex(mid)+CommandHex.READ_SECTOR_SUFFIX);
			} catch (SerialPortException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}else if("poultry-conn".equals(command)) {
			try {
				if(port != null) {
					logger.debug("close port.");
					port.close();
					port = null;
				}
				
				if(port == null) {
					logger.debug("try conn port");
					port = sps.connPort(content);
					logger.debug("conn port end:"+port);
				}
				try {
					sps.writeHex(port, CommandHex.CONN);
				} catch (SerialPortException e) {
					this.sendText("poultry-conn-fail"+"连接失败，发送数据失败。");
					return;
				}
				this.sleep(500);
				try {
					byte[] connRes = sps.readFromPort(port);
					String hex = ByteUtil.bytesToHex(connRes);
					if(hex.startsWith(CommandHex.CONN_SUCC_PREFIX)) {
						this.sendText("poultry-conn-succ");
					}
				} catch (SerialPortException e) {
					this.sendText("poultry-conn-fail"+"发送连接指令后，硬件返回数据读取错误。");
				}
				
			} catch (NoSuchPortException e) {
				e.printStackTrace();
				this.sendText("poultry-conn-fail"+"连接失败，发送连接指令后，硬件返回数据读取错误。");
			} catch (PortInUseException e) {
				e.printStackTrace();
				this.sendText("poultry-conn-fail"+"连接失败，串口被拔掉或已经被占用。");
			} catch (UnsupportedCommOperationException e) {
				e.printStackTrace();
				this.sendText("poultry-conn-fail"+"连接错误，不支持的操作。");
			}
			
		}else if("poultry-find".equals(command)) {
			try {
				sps.writeHex(port, CommandHex.FIND_CARD);
				this.sleep(500);
				byte[] resp = sps.readFromPort(port);
				String hex = ByteUtil.bytesToHex(resp);
				if(hex.length() == CommandHex.FIND_CARD_SUCC.length()) {
					//this.sendLog("log", "寻卡成功！");
					sps.writeHex(port, CommandHex.KILL_CONFLICT);
					this.sleep(500);
					resp = sps.readFromPort(port);
					hex = ByteUtil.bytesToHex(resp);
					if(hex.startsWith(CommandHex.KILL_CONFLICT_SUCC_PREFIX)) {
						String cardId = hex.substring(CommandHex.KILL_CONFLICT_SUCC_PREFIX.length()+1);
						this.data.put("cardId", cardId);
						this.sendText("poultry-find-succ"+cardId);
					}else {
						this.sendText("poultry-find-fail"+"寻卡失败。");
					}
				}else{
					this.sendText("poultry-find-fail"+"寻卡失败。");
				}
			} catch (SerialPortException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				this.sendText("poultry-find-fail"+"寻卡失败。");
			}
		}else if("".equals(command)) {

		}
	}

	@Override
	@OnError
	public void onError(Session session, Throwable throwable) {
		logger.debug("ws onerror:"+session.getId());
		throwable.printStackTrace();
	}

	@Override
	@OnClose
	public void onClose(Session session, CloseReason reason) {
		logger.debug("ws close.");
		wss.remove(this);
	}
	
	private void sendLog(String com,String msg) {
		this.sendText(com+":"+TimeUtil.hhmmss()+":"+msg);
	}
	private void sendResult(String com,String msg) {
		this.sendText(com+":"+msg);
	}
	private void sleep(int m) {
		try {
			Thread.sleep(m);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
